import logging
from tempfile import NamedTemporaryFile
from decorator import decorator
from pathlib import Path
from lly.vim.config_mapping import VimMappingManger
from lly.logconfig import logger,vim_logger
from lly.brower import chrome
import re
'''
vim帮助模块
'''
# 关于buffer的临时结果
B_TMP_DATA = ('tmp_data', 'b:tmp_data')
# 关于buffer的执行断言结果
B_TMP_ASSERT = ('tmp_assert', 'b:tmp_assert')
# feedkeys的回车键
KEY_CR = '\<CR>'
CALL_VIM_FUNCTION = '_call_vim_function'


@decorator
def try_except(func, *args, **kwargs):
    try:
        return func(*args, **kwargs)
    except Exception as err:
        logger.exception(err)


class Nvim(object):
    '''
    Nvim plugin 类
    '''
    vim_mapping = None
    _config_dir = None

    def __init__(self, nvim):
        self.nvim = nvim
        self.logger = vim_logger
        self.logger.setLevel(logging.INFO)
        self.logger.info('NVIM: __init__')

    def mapping_manager(self):
        if Nvim.vim_mapping is None:
            Nvim.vim_mapping = VimMappingManger(self.nvim,
                                                result_path=NamedTemporaryFile('w+t').name)
            logger.info(
                f"{ str(Nvim.vim_mapping) } == { str(self.vim_mapping) }")
        return Nvim.vim_mapping

    def config_dir(self):
        '''得到配置文件路径'''
        if Nvim._config_dir is None:
            for path in self.nvim.list_runtime_paths():
                Nvim._config_dir = self.__get_config_dir(path)
                if Nvim._config_dir is not None:
                    break
        return Nvim._config_dir

    def __get_config_dir(self, path):
        '''
        得到配置文件路径，如果没有
        '''
        #  self.logger.info(f"path: {path}")
        result = None
        for path in list(Path(path).glob(r"rplugin/python3/config")):
            if path is not None:
                result = str(path)
                self.logger.info(result)
                break
        return result

    def feedkeys(self,  keys, mode='m'):
        '''
        调用nvim的feedkeys()函数，但是可以输入特殊键
        '''
        func = self.function('feedkeys', Sink(f'"{keys}"'), mode)
        self.nvim.command(f'call {func}')

    def function(self, name, *args):
        '''
        返回vim函数的字符串
        '''
        arg = ','.join(repr(arg) for arg in args)
        arg = '' if arg is None else arg
        result = f"{name}({arg})"
        self.logger.info(result, exc_info=True)
        self.logger.info("function", result)
        return result

    def func_exists(self, name):
        '''
        判断vim函数是否存在
        '''
        exists = self.nvim.call("exists", f"*{name}")
        return exists != 0

    def product_sink(self, *args):
        return Sink(self.function('function', CALL_VIM_FUNCTION, [*args]))

    def echo(self, message):
        '''call nvim echo
        '''
        self.nvim.command(f"echo {repr(message)}")

    def fzf_run(self, source, sink, reverse=False, fullscreen=False, multi=False):
        '''
        fzf使用
        '''
        options = []
        info = {'source': source, 'options': options}
        if sink is not None:
            info['sink'] = sink
        if reverse:
            options.append('--reverse')
        if multi:
            options.append('--multi')
        fzf_wrap = self.function('fzf#wrap', info, 1 if fullscreen
                                 else 0)
        fzf_run = self.function('fzf#run', Sink(fzf_wrap))
        fzf_run = f"call {fzf_run}"
        self.nvim.command(fzf_run)

    def command(self, cmd):
        '''执行cmd
        若cmd是str，当作vim函数执行
        若cmd是list，当作python函数执行
        '''
        if isinstance(cmd, str):
            self.nvim.command(f"call {cmd}")
        elif isinstance(cmd, list) or isinstance(cmd, tuple):
            cmd[0](*cmd[1:])

    def exec_macro(self, servers, args):
        server_regx = re.compile(r"\s*(?P<index>\d+)]")
        for arg in args:
            match = server_regx.match(arg)
            if match:
                target_index = int(match['index'])
                for index, server in enumerate(servers):
                    if target_index == index:
                        if len(server) == 2:
                            cmd = server[1]
                            self.command(cmd)
                        else:
                            current_status = server[3]
                            cmd = server[2] if current_status else server[1]
                            self.command(cmd)
                            server[3] = not current_status
                        if index > 0:
                            top = servers.pop(index)
                            servers.insert(0, top)
                        break

    def preview(self, path):
        chrome.webBrower.openUrl(path)

    def select_analysis_config(self, directory=""):
        '''显示分析文件，以供选择
        '''
        analysis_config_list = []
        for path in Path(self.config_dir()+'/analysis/'+directory).glob(r"*"):
            analysis_config_list.append(str(path))
        self.fzf_run(analysis_config_list, self.product_sink('_analysis_file'))


class Sink(str):
    '''
    构造fzf需要的sink
    '''

    def __init__(self, sink, is_funcr=True):
        self.sink = sink
        self.is_funcr = is_funcr

    def __str__(self):
        return self.__repr__()

    def __repr__(self):
        if self.is_funcr:
            return self.sink
        return repr(self.sink)


HIGHLIGHT_DICT = {
    'E': 'ErrorMsg',
    'W': 'WarningMsg',
    'D': 'Debug',
}
